#include "DataBase/DataBase.h"

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <hi_net_api.h>

#include "cmsis_os2.h"
#include "los_typedef.h"
#include "ohos_init.h"
#include "securec.h"
#include "wifi_device.h"
#include "wifi_error_code.h"

#define DEF_TIMEOUT 15
#define ONE_SECOND 1
#define DHCP_DELAY 100

static int WaitConnectResult(void);
static void OnWifiScanStateChangedHandler(int state, int size);
static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info);
static void OnHotspotStaJoinHandler(StationInfo *info);
static void OnHotspotStateChangedHandler(int state);
static void OnHotspotStaLeaveHandler(StationInfo *info);

static int g_staScanSuccess = 0;
static int g_ConnectSuccess = 0;
static int g_ssid_count = 0;
static struct netif *g_lwip_netif = NULL;
static WifiEvent g_wifiEventHandler = {0};
WifiErrorCode error;

#define SELECT_WLAN_PORT "wlan0"

int WIFI_Init(void)
{
    g_wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedHandler;
    g_wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedHandler;
    g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
    g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
    g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
    error = RegisterWifiEvent(&g_wifiEventHandler);
    if (error != WIFI_SUCCESS)
    {
        printf("register wifi event fail!\r\n");
        return -1;
    }
    // 使能WIFI
    if (EnableWifi() != WIFI_SUCCESS)
    {
        printf("EnableWifi failed, error = %d\r\n", error);
        return -1;
    }
    // 判断WIFI是否激活
    if (IsWifiActive() == 0)
    {
        printf("Wifi station is not actived.\r\n");
        return -1;
    }

    g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);
    if (g_lwip_netif)
    {
        dhcp_start(g_lwip_netif);
        printf("begain to dhcp\r\n");
    }
    return 0;
}

static void OnWifiScanStateChangedHandler(int state, int size)
{
    if (size > 0)
    {
        g_ssid_count = size;
        g_staScanSuccess = 1;
    }
    printf("callback function for wifi scan:%d, %d\r\n", state, size);
    return;
}

static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info)
{
    if (info == NULL)
    {
        printf("WifiConnectionChanged:info is null, stat is %d.\n", state);
    }
    else
    {
        if (state == WIFI_STATE_AVALIABLE)
        {
            g_ConnectSuccess = 1;
        }
        else
        {
            g_ConnectSuccess = 0;
        }
    }
}

static void OnHotspotStaJoinHandler(StationInfo *info)
{
    (void)info;
    printf("STA join AP\n");
    return;
}

static void OnHotspotStaLeaveHandler(StationInfo *info)
{
    (void)info;
    printf("HotspotStaLeave:info is null.\n");
    return;
}

static void OnHotspotStateChangedHandler(int state)
{
    printf("HotspotStateChanged:state is %d.\n", state);
    return;
}

static int WaitConnectResult(void)
{
    int ConnectTimeout = DEF_TIMEOUT;
    while (ConnectTimeout > 0)
    {
        sleep(ONE_SECOND);
        ConnectTimeout--;
        if (g_ConnectSuccess == 1)
        {
            printf("WaitConnectResult:wait success[%d]s\n", (DEF_TIMEOUT - ConnectTimeout));
            break;
        }
    }
    if (ConnectTimeout <= 0)
    {
        printf("WaitConnectResult:timeout!\n");
        return 0;
    }
    return 1;
}

WifiErrorCode WIFI_ConnectAndSave(const WifiDeviceConfig *config, int save)
{
    static int netid = -1;
    WifiErrorCode err = WIFI_SUCCESS;

    if (netid != -1)
    {
        if ((err = Disconnect()) || (err = RemoveDevice(netid)))
        {
            printf("ERROR: WIFI_ConnectAndSave->Disconnect and Remove %d\r\n", err);
            return err;
        }
    }

    if ((err = AddDeviceConfig(config, &netid)) != WIFI_SUCCESS && netid != -1)
    {
        printf("ERROR: WIFI_ConnectAndSave->AddDeviceConfig %d netid=%d\r\n", err, netid);
        return err;
    }

    printf("netid = %d\r\n", netid);

    if ((err = ConnectTo(netid)) == WIFI_SUCCESS && WaitConnectResult() == 1)
    {
        if (save)
        {
            err = db_save_wifi_config(config);
        }
    }
    else
    {
        printf("ERROR: WIFI_ConnectAndSave->ConnectTo %d\r\n", err);
    }
    return err;
}

WifiErrorCode WIFI_Connect(void)
{
    WifiDeviceConfig config = {.ipType = DHCP};
    if (db_get_wifi_config(&config) == 0)
    {
        return WIFI_ConnectAndSave(&config, FALSE);
    }
    else
    {
        printf("ERROR: WIFI_Connect->db_get_wifi_config\r\n");
        return ERROR_WIFI_UNKNOWN;
    }
}

int WIFI_isConnected(ip_addr_t *ip_addr)
{
    WifiLinkedInfo info = {0};
    if (GetLinkedInfo(&info) == WIFI_SUCCESS)
    {
        if (ip_addr)
        {
            ip_addr->addr = info.ipAddress;
        }
        return info.connState;
    }
    return 0;
}

WifiErrorCode WIFI_getSSID(char *ssid, int size)
{
    WifiDeviceConfig config = {.ipType = DHCP};

    if (ssid == NULL || size < WIFI_MAX_SSID_LEN)
    {
        return ERROR_WIFI_INVALID_ARGS;
    }

    if (db_get_wifi_config(&config) == 0)
    {
        strcpy_s(ssid, size, config.ssid);
        return WIFI_SUCCESS;
    }
    return ERROR_WIFI_UNKNOWN;
}